{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "※ Threadの実行結果を確認するためにbashのコマンド実行でrubyを動かしてます"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Threadクラス\n",
    "\n",
    "* Threadクラス\n",
    "    * スレッドを表すクラス\n",
    "    * 並行(マルチスレッド)プログラミングが可能となる\n",
    "    * Ruby1.9よりネイティブスレッドを用いて実装されている\n",
    "        * 同時に実行されるネイティブスレッドは常に一つ\n",
    "            * Giant VM lockを有しているため\n",
    "    * メインスレッド\n",
    "        * プログラムの開始と同時に生成されるスレッド\n",
    "        * これが終了すると他のスレッドも含めてプログラムが終了する\n",
    "    * カレントスレッド\n",
    "        * 現在実行中のスレッド\n",
    "    * スレッドの実行はスケジューリングされている\n",
    "        * 優先順位付きのラウンドロビン・スケジューリングという方式で管理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッドの生成\n",
    "\n",
    "* メソッド\n",
    "    * Thread.new\n",
    "        * インスタンス化することでスレッドを生成する\n",
    "        * initializeメソッドが呼ばれる\n",
    "    * Thread.start, Thread.fork\n",
    "        * スレッドを生成する\n",
    "        * initializeメソッドは呼ばれない"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Thread:0x007fd02ca5a038@/tmp/thread.rb:2 run>\n",
      "#<Thread:0x007fd02ca59d40@/tmp/thread.rb:3 run>\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "p t = Thread.new{ sleep 1}\n",
    "p t = Thread.new(3){|t| sleep t}\n",
    "EOS\n",
    "\n",
    "### 実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッドの状態\n",
    "\n",
    "* メソッド\n",
    "    * status\n",
    "        * 生成したスレッドの実行状態を保持\n",
    "    * alive?\n",
    "        * スレッドが生きているかを確認\n",
    "    * stop?\n",
    "        * スレッドが終了、もしくは停止していることを確認\n",
    "        \n",
    "* 状態\n",
    "    * run\n",
    "        * 実行中、または実行可能状態\n",
    "            * 生成直後\n",
    "            * runメソッドやwakeupメソッドで起こされたスレッド\n",
    "            * statusメソッドで確認するとrunが返る\n",
    "    * sleep\n",
    "        * 一時停止状態\n",
    "            * Thread.stopメソッドやjoinメソッドにより一時停止されたスレッド\n",
    "            * statusメソッドで確認するとsleepが返る\n",
    "    * aborting\n",
    "        * 終了処理中\n",
    "            * killメソッドなどで終了されるスレッドは一時的にこの状態になる\n",
    "            * statusメソッドで確認するとabortingが返る\n",
    "    * dead\n",
    "        * <font color=\"red\">正常終了したスレッド</font>\n",
    "            * killメソッドで終了したときや通常終了した状態\n",
    "            * statusメソッドで確認すると<font color=\"red\">false</font>が返る\n",
    "        * <font color=\"red\">異常終了したスレッド</font>\n",
    "            * 例外など\n",
    "            * statusメソッドで確認すると<font color=\"red\">nil</font>が返る"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Thread:0x007fd69a859800@/tmp/thread.rb:2 run>\n",
      "スレッドが生きている事の確認\n",
      "sleep\n",
      "true\n",
      "true\n",
      "\n",
      "スレッドが停止している事の確認\n",
      "sleep\n",
      "true\n",
      "true\n",
      "\n",
      "スレッドが終了している事の確認\n",
      "false\n",
      "false\n",
      "true\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "p t = Thread.new{ sleep 2}\n",
    "\n",
    "puts \"スレッドが生きている事の確認\"\n",
    "puts t.status\n",
    "puts t.alive?\n",
    "puts t.stop?\n",
    "puts\n",
    "\n",
    "sleep 1\n",
    "\n",
    "puts \"スレッドが停止している事の確認\"\n",
    "puts t.status\n",
    "puts t.alive?\n",
    "puts t.stop?\n",
    "puts\n",
    "\n",
    "sleep 2\n",
    "\n",
    "puts \"スレッドが終了している事の確認\"\n",
    "puts t.status\n",
    "puts t.alive?\n",
    "puts t.stop?\n",
    "\n",
    "EOS\n",
    "\n",
    "### 実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッドの再開、一時停止、終了\n",
    "\n",
    "* メソッド\n",
    "    * 再開\n",
    "        * run\n",
    "            * スレッドを再開する\n",
    "        * wakeup\n",
    "            * 実行可能状態にする\n",
    "            * 実行されるかどうかは他のスレッドの状況による\n",
    "    * 一時停止状態\n",
    "        * Thread.stop\n",
    "            * スレッドを停止している状態\n",
    "        * join\n",
    "            * 他のスレッドが終了するのを待っている状態\n",
    "    * 終了\n",
    "        * kill, exit\n",
    "            * スレッドを終了する\n",
    "            * ensure節があれば実行する\n",
    "        * kill!, exit!\n",
    "            * スレッドを終了する\n",
    "            * ensure節があっても実行されない\n",
    "        * Thread.kill\n",
    "            * 指定したスレッドのexitメソッドを呼び出す\n",
    "        * Thread.exit\n",
    "            * カレントスレッドのexitメソッドを呼び出す"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "OK\n",
      "#<Thread:0x007fcef339eaf8>\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "t = Thread.new do\n",
    "  Thread.stop\n",
    "  puts \"OK\\n\"\n",
    "end\n",
    "\n",
    "### スレッドがsleep状態になるのを待つ\n",
    "sleep 1\n",
    "\n",
    "### スレッドの再開\n",
    "puts t.run\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Thread:0x007f9f9620b740@/tmp/thread.rb:1 dead>\n",
      "false\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "t = Thread.new do\n",
    "  Thread.exit\n",
    "end\n",
    "\n",
    "### スレッドが終了するのを待つ\n",
    "sleep 1\n",
    "\n",
    "### スレッドの状態確認\n",
    "p t\n",
    "puts t.status\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッド終了時のensure節\n",
    "\n",
    "* ensure節がある場合\n",
    "    * スレッド終了時に実行される\n",
    "    * 他のスレッドからkillで終了させられたときも実行する\n",
    "    * kill!メソッドが呼び出されたときは実行されない\n",
    "        * メインスレッドのみkill!メソッドが呼ばれた場合は各スレッドでは実行される"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Killed.\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "t = Thread.new do\n",
    "  begin\n",
    "    sleep 10000\n",
    "  ensure\n",
    "    puts \"Killed.\"\n",
    "  end\n",
    "end\n",
    "\n",
    "### スレッドがsleepになるのを待つ\n",
    "sleep 1\n",
    "\n",
    "### スレッドをkillする\n",
    "t.kill\n",
    "\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッド中の例外\n",
    "\n",
    "* スレッド中で例外発生\n",
    "    * rescureで捕捉しなかった場合\n",
    "        * 通常はそのスレッドのみが警告なしに終了される\n",
    "        * joinメソッドで待っている他のスレッドがある場合は待っているスレッドに対して同じ例外が再度発生する\n",
    "* 例外が発生した場合のプログラム自体の終了させ方\n",
    "    * Thread.abort_on_exceptionメソッドにtrueを設定する\n",
    "    * 特定のスレッドのabort_on_exceptionメソッドにtrueを設定する\n",
    "    * グローバル変数`$DEBUG`にtrueを設定し、プログラムを-d付きオプションで実行する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Thread:0x007fad921e3b28@/tmp/thread.rb:2 dead>\n",
      "nil\n",
      "Raise exception\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "t = Thread.new {Thread.pass; raise \"Raise exception\"}\n",
    "\n",
    "### tは異常終了\n",
    "sleep 1\n",
    "p t\n",
    "p t.status\n",
    "\n",
    "### eはtを待つ\n",
    "e = Thread.new do\n",
    "  begin\n",
    "    p t.join\n",
    "  rescue => ex\n",
    "    p ex.message\n",
    "  end\n",
    "end\n",
    "\n",
    "### pryで実行すると以下のようなメッセージが表示される\n",
    "puts \"Raise exception\"\n",
    "\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "Thread.new do\n",
    "  Thread.raise \"Raise exception\"\n",
    "  begin\n",
    "    sleep 1\n",
    "  rescue => ex\n",
    "    puts ex\n",
    "  end\n",
    "end\n",
    "\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッドのデッドロック\n",
    "\n",
    "* 以下の状態になるとデッドロックとみなしてfatalが発生し、プログラムが終了する\n",
    "    * スレッドが複数ある\n",
    "    * 全てのスレッドが停止状態\n",
    "        * メインスレッドのみがThread.stopで停止している状態ではfatalは発生しない\n",
    "    * IO待ちのスレッドが存在しない"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Thread:0x007f89c19f2c78@/tmp/thread.rb:2 sleep>\n",
      "sleep\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/thread.rb:4:in `stop': No live threads left. Deadlock? (fatal)\n",
      "\tfrom /tmp/thread.rb:4:in `<main>'\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "t = Thread.new { Thread.stop }\n",
    "begin\n",
    "  Thread.stop\n",
    "rescure\n",
    "  puts ex\n",
    "ensure\n",
    "  sleep 1\n",
    "  p t\n",
    "  puts t.status\n",
    "end\n",
    "  \n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッドのリスト\n",
    "\n",
    "* メソッド\n",
    "    * Thread.list\n",
    "        * 実行中のスレッドのリストを表示する\n",
    "        * スレッドが生成されていない場合はメインスレッドのみ表示する\n",
    "    * Thread.main\n",
    "        * メインスレッドを表示する\n",
    "    * Thread.current\n",
    "        * カレントスレッドを表示する\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#<Thread:0x007fcbd407f3d0 run>]\n",
      "\n",
      "[#<Thread:0x007fcbd407f3d0 run>, #<Thread:0x007fcbd3a7adb8@/tmp/thread.rb:5 run>]\n",
      "\n",
      "#<Thread:0x007fcbd407f3d0 run>\n",
      "#<Thread:0x007fcbd407f3d0 run>\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "p Thread.list\n",
    "puts \n",
    "\n",
    "t = Thread.new { Thread.stop }\n",
    "p Thread.list\n",
    "puts \n",
    "\n",
    "p Thread.main\n",
    "p Thread.current\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッドの切り替え\n",
    "\n",
    "* メソッド\n",
    "    * Thread.pass\n",
    "        * 実行中のスレッドの状態を変えずに他のスレッドに実行権を譲る"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[#<Thread:0x007f8e838833d0 run>, #<Thread:0x007f8e84aa3380@/tmp/thread.rb:2 run>]\n",
      "\n",
      "[#<Thread:0x007f8e838833d0 run>]\n",
      "#<Thread:0x007f8e84aa3380@/tmp/thread.rb:2 dead>\n",
      "nil\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "t = Thread.new { Thread.pass; raise \"Error\" }\n",
    "p Thread.list\n",
    "puts\n",
    "\n",
    "sleep 1\n",
    "p Thread.list\n",
    "p t\n",
    "p t.status\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッドの終了を待つ\n",
    "\n",
    "* join\n",
    "    * スレッドの実行終了までカレントスレッドを停止する\n",
    "        * 通常スレッドは生成と同時に実行される\n",
    "        * ラウンドロビンにより何時終了するかわからない\n",
    "* value\n",
    "    * スレッドの実行終了までカレントスレッドを停止する\n",
    "    * スレッドのブロックの評価結果を返す"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n",
      "1\n",
      "4\n",
      "9\n",
      "16\n",
      "5\n",
      "\n",
      "[#<Thread:0x007fa3490833d0 run>]\n",
      "#<Thread:0x007fa34991cd98@/tmp/thread.rb:4 dead>\n",
      "false\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "#Thread.critical\n",
    "\n",
    "t = Thread.new { Thread.pass; 5.times{|i| puts i**2; sleep 1} }\n",
    "\n",
    "### t.joinがあるとスレッドの処理が終わるまで待つ\n",
    "#puts t.join\n",
    "### t.valueは評価結果を返す\n",
    "puts t.value\n",
    "puts\n",
    "\n",
    "p Thread.list\n",
    "p t\n",
    "p t.status\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッドの優先度\n",
    "\n",
    "* メソッド\n",
    "    * priority\n",
    "        * 優先度を決める\n",
    "        * 値が大きいほど優先される\n",
    "        * メインスレッドのデフォルトは0\n",
    "        * 新しく生成されるスレッドは親スレッドの設定を引き継ぐ\n",
    "    * priority=\n",
    "        * 優先度を設定する\n",
    "        * 大きな値を設定しても以下の例では3が最大になる？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Thread:0x007fd74b204e30@/tmp/thread.rb:2 run>\n",
      "0\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "p t = Thread.new(10) { |t|  sleep t}\n",
    "sleep 1\n",
    "p t.priority\n",
    "t.priority = 10\n",
    "puts t.priority\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スレッド固有のデータ\n",
    "\n",
    "* データに固有の名前をつけて保存できる\n",
    "* メソッド\n",
    "    * key?\n",
    "        * データが保存されているか確認する\n",
    "    * keys\n",
    "        * 保持している名前を取得する"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "#<Thread:0x007f9ec2883390 run>\n",
      "Foo\n",
      "true\n",
      "[:foo]\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "p t = Thread.current\n",
    "t[:foo] = \"Foo\"\n",
    "puts t[:foo]\n",
    "puts t.key?(:foo)\n",
    "p t.keys\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\"wait\"\n",
      "\"start\"\n",
      "\"end\"\n",
      "thread-0 start\n",
      "thread-1 start\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=thread\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "t = Thread.new do\n",
    "  p \"start\"\n",
    "  sleep 2\n",
    "  p \"end\"\n",
    "end\n",
    "p \"wait\"\n",
    "t.join\n",
    "\n",
    "3.times do |i|\n",
    "  Thread.start(i) do |index|\n",
    "    puts \"thread-#{index} start\"\n",
    "  end\n",
    "end\n",
    "\n",
    "### pryだと以下のように出力される\n",
    "# ===\n",
    "# thread-0 start\n",
    "# thread-1 start\n",
    "# => 3\n",
    "# [5] pry(main)> thread-2 start\n",
    "# ===\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Fiberクラス\n",
    "\n",
    "* スレッドと同じように複数のタスクを切り替えて並列処理をするための機能\n",
    "    * Ruby1.9から\n",
    "* スレッドと異なる点\n",
    "    * スレッドはタスクの切り替えをOSや仮想マシンが行う\n",
    "    * ファイバは切替のタイミングを開発者がプログラム内で明示的に記述する\n",
    "* 他の言語ではコルーチンやセミコルーチンと呼ばれる軽量スレッドを提供するクラス\n",
    "    * スレッドとの相違点\n",
    "        * 明示的に指定しない限りコンテキストが切り替わらない\n",
    "        * 親子関係を持つ\n",
    "* メソッド\n",
    "    * Fiber.new\n",
    "        * ブロックを渡すとFiberクラスのオブジェクトが生成される\n",
    "    * resume\n",
    "        * コンテキストをファイバーに切り替える\n",
    "        * Fiber.yieldが呼び出されるまでファイバ内の処理を実行する\n",
    "* Fiber.yield\n",
    "        * 親である呼び出し元にコンテキストを切り替える"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "parent -> child\n",
      "hello\n",
      "child -> parent\n",
      "parent -> child\n",
      "hello\n",
      "child -> parent\n",
      "parent -> child\n",
      "hello\n",
      "child -> parent\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=fiber\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "f = Fiber.new do\n",
    "  loop do\n",
    "    puts 'hello'\n",
    "    puts 'child -> parent'\n",
    "    Fiber.yield\n",
    "  end\n",
    "end\n",
    "\n",
    "3.times do\n",
    "  puts 'parent -> child'\n",
    "  f.resume\n",
    "end\n",
    "\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "nil\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/tmp/fiber.rb:13:in `resume': dead fiber called (FiberError)\n",
      "\tfrom /tmp/fiber.rb:13:in `<main>'\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "name=fiber\n",
    "\n",
    "### ソースの編集\n",
    "cat <<- EOS > /tmp/${name}.rb\n",
    "\n",
    "f = Fiber.new do\n",
    "  (1..3).each do |i|\n",
    "    Fiber.yield i\n",
    "  end\n",
    "  nil\n",
    "end\n",
    "\n",
    "p f.resume\n",
    "p f.resume\n",
    "p f.resume\n",
    "p f.resume\n",
    "p f.resume\n",
    "EOS\n",
    "\n",
    "### ruby実行\n",
    "ruby /tmp/${name}.rb"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
